require 'base/servlet.rb'
require 'model/item.rb'
require 'model/user.rb'


class MiniTodoApp < DemorubyServlet
  Demoruby::define_basic_methods self

  def self.config
    {:mount_point => '/todo', :port => 8888}
  end

  def self.init_app
    DataMapper.setup(:default, 'mysql://localhost/mini_todo')
  end

  def login(context)
    user = nil
    if context.post? then
      user = User.login(context.req.query['name'],
                        context.req.query['pass'])
    else
      user = User.find_by_ticket(context.store['ticket'])
    end
    if user.nil? then
      context.login_failed = true
    else
      context.store['ticket'] = user.ticket
      forward_to('list')
    end
  end

  def create_account(context)
    if not context.post? then
      return
    end
    # post
    if !matches_password(context) then
      context.password_mismatched = true
      return
    end
    # password matched
    user_name = context.req.query['name']
    user = User.find_by_name(user_name)
    if user.nil? then
      User.new_user(user_name, user_pass)
      redirect_to('login')
    else
      context.already_exists = true
    end
  end

  def matches_password(context)
    context.req.query['pass1'] == context.req.query['pass2']
  end

  def list(context)
    #if ng_ticket?(context) then
    #  redirect_to('login')
    #  return
    #end
    if context.path_args.blank? then
      context.todo_list = Item.yet # all(:done => false, :order => [:update_time.desc])
    else
      year = context.path_args[0]
      month = context.path_args[1] rescue nil
      day = context.path_args[2] rescue nil
      context.todo_list = Item.yet(year, month, day)
    end
  end

  class SearchQuery
    attr_reader :parts
    def initialize(query)
      @parts = {}
      # TODO エスケープは保留
      query.split(/,/).each do |part|
        @parts[$1.intern] = $2 if part =~ /(^\:[a-z]+)\s+(.+$)/
      end
      @parts[:body] = query if @parts.empty?
    end
    def to_conditions
      # TODO 解析
      query = {}
      if not @parts[:body].nil? then
        query[:body.like] = "%#{@parts[:body]}%"
      end
      return query
    end
  end

  def search(context)
    query = context.req.query['search-query']
    if not query.blank? then
      conds = SearchQuery.new(query).to_conditions
      context.todo_list = Item.all(conds)
    end
    context.action = 'list'
  end

  class ItemBodyParser
    attr_reader :tags, :body
    def initialize
      @tags = []
    end
    def parse(str)
      if str =~ /(\[.+\])+\s*(.+)/ then
        @body = $2
        $1.gsub(/\[[^\]]+\]/) do |m|
          @tags << m[1..-2]
        end
      else
        @body = str
      end
      return @body, @tags
    end
  end

  def save_item(context)
    if context.post? then
      id   = context.req.query['id']
      original_body = context.req.query['value']
      body, tags = ItemBodyParser.new.parse(original_body)

      item = Item.get(id)
      if item.nil? then
        item = Item.create(:body => body)
      else
        item.body = body
      end

      if not tags.nil? then
        tags.each do |tag|
          item.tags << Tag.first_or_create(:body => tag)
        end
      end
      item.save
    end
    context.res.body = original_body
    context.rhtml_response = false
  end
      
  def ng_ticket?(context)
    # TODO Cookie 方式に変えないとね...
    user = User.find_by_ticket(context.store['ticket'])
    user.nil?
  end

  def logout(context)
    User.logout(context.store['ticket'])
    context.store['ticket'] = nil
    context.logout_failed = false
  end
end

